package phidgetmotion.phidget;

import java.util.Iterator;
import java.util.LinkedList;

import phidgetmotion.classifier.FeatureInputListener;
import phidgetmotion.classifier.FeatureVector;

import com.phidgets.event.AccelerationChangeEvent;
import com.phidgets.event.AccelerationChangeListener;
import com.phidgets.event.AttachEvent;
import com.phidgets.event.AttachListener;
import com.phidgets.event.DetachEvent;
import com.phidgets.event.DetachListener;

public class FeatureGenerator {
	private int updateInterval;
	private Object featureVectorMutex = new Object();
	private FeatureVector featureVector = new FeatureVector();
	
	private LinkedList<FeatureInputListener> listeners = new LinkedList<FeatureInputListener>();

	private AccelerationChangeListener changeListener = new AccelerationChangeListener() {
		@Override
		public void accelerationChanged(AccelerationChangeEvent event) {
			synchronized(featureVectorMutex)  {
				featureVector.addInput(event.getIndex(), event.getValue());
			}
		}
	};
	
	private TimerThread timer;
	
	private class TimerThread extends Thread{
		@Override
		public void run() {
			try {
				synchronized(featureVectorMutex)  {
					featureVector = new FeatureVector();
				}
				while(true)
				{
					sleep(updateInterval);

					synchronized(featureVectorMutex)  {
						featureVector.finished();
						fireFeatureInput(featureVector);
						featureVector = new FeatureVector();
					}
				}
			} catch (InterruptedException e) {
				// Timer stop
			}
		}
	};
	
	private AttachListener attachListener = new AttachListener() {
		@Override
		public void attached(AttachEvent arg0) {
			timer = new TimerThread();
			timer.start();
		}
	};
	
	private DetachListener detachListener = new DetachListener() {
		@Override
		public void detached(DetachEvent arg0) {
			timer.interrupt();
			timer = null;
		}
	};
	
	public FeatureGenerator(int updateInterval) {
		this.updateInterval = updateInterval;
		Accelerometer.addAccelerationChangeListener(changeListener);
		Accelerometer.addAttachListener(attachListener);
		Accelerometer.addDetachListener(detachListener);
		if(Accelerometer.isConnected()) {
			timer = new TimerThread();
			timer.start();
		}
	}

	public void close() {
		Accelerometer.removeAccelerationChangeListener(changeListener);
		if(timer!=null){
			timer.interrupt();
			timer = null;
		}
	}
	
	public void addFeatureInputListener(FeatureInputListener l){
		listeners.addFirst(l);
	}
	
	private void fireFeatureInput(FeatureVector vector){
		Iterator<FeatureInputListener> iter = listeners.iterator();
		while(iter.hasNext()){
			iter.next().featureInput(vector);
		}
	}
	
	public boolean removeFeatureInputListener(FeatureInputListener l){
		return listeners.remove(l);
	}

	public int getUpdateInterval() {
		return updateInterval;
	}

	public void setUpdateInterval(int updateInterval) {
		this.updateInterval = updateInterval;
	}
}
